from typing import List, Optional
from uuid import UUID

from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends, HTTPException

from fastapi_template.common.responses import CommonResp
from fastapi_template.containers import Container
from fastapi_template.domains.role import (RoleCreateDTO, RoleDTO, RoleFacade,
                                           RoleUpdateDTO)

router = APIRouter(prefix="/roles", tags=["roles"])


@router.post("", response_model=CommonResp[RoleDTO])
@inject
async def create_role(
    role_data: RoleCreateDTO,
    role_facade: RoleFacade = Depends(Provide[Container.role_facade])
) -> CommonResp[RoleDTO]:
    """Create a new role."""
    try:
        role = await role_facade.create_role(role_data)
        return CommonResp.ok(data=role)
    except Exception as e:
        return CommonResp.fail(msg=str(e))


@router.get("", response_model=CommonResp[List[RoleDTO]])
@inject
async def get_all_roles(role_facade: RoleFacade = Depends(
    Provide[Container.role_facade])) -> CommonResp[List[RoleDTO]]:
    """Get all roles."""
    roles = await role_facade.get_all_roles()
    return CommonResp.ok(data=roles)


@router.get("/{role_id}", response_model=CommonResp[Optional[RoleDTO]])
@inject
async def get_role(
    role_id: UUID,
    role_facade: RoleFacade = Depends(Provide[Container.role_facade])
) -> CommonResp[Optional[RoleDTO]]:
    """Get role by ID."""
    role = await role_facade.get_role_by_id(role_id)
    if not role:
        raise HTTPException(status_code=404, detail="Role not found")
    return CommonResp.ok(data=role)


@router.get("/{role_id}/children", response_model=CommonResp[List[RoleDTO]])
@inject
async def get_child_roles(
    role_id: UUID,
    role_facade: RoleFacade = Depends(Provide[Container.role_facade])
) -> CommonResp[List[RoleDTO]]:
    """Get all child roles of a role."""
    roles = await role_facade.get_child_roles(role_id)
    return CommonResp.ok(data=roles)


@router.put("/{role_id}", response_model=CommonResp[Optional[RoleDTO]])
@inject
async def update_role(
    role_id: UUID,
    role_data: RoleUpdateDTO,
    role_facade: RoleFacade = Depends(Provide[Container.role_facade])
) -> CommonResp[Optional[RoleDTO]]:
    """Update role information."""
    role = await role_facade.update_role(role_id, role_data)
    if not role:
        raise HTTPException(status_code=404, detail="Role not found")
    return CommonResp.ok(data=role)


@router.delete("/{role_id}", response_model=CommonResp[bool])
@inject
async def delete_role(
    role_id: UUID,
    role_facade: RoleFacade = Depends(Provide[Container.role_facade])
) -> CommonResp[bool]:
    """Delete role by ID."""
    success = await role_facade.delete_role(role_id)
    if not success:
        raise HTTPException(status_code=404, detail="Role not found")
    return CommonResp.ok(data=True)
